package pri.zxx.nio;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Set;

/**
 * @author Twilight
 * @desc 网络io
 * @createTime 2020-05-16-22:47
 */
@Slf4j
public class SocketTest {

    /**
     * 1.通道channel
     * 2.buffer
     * 3.选择器selector  selectableChannel
     */

    @SneakyThrows
    @Test
    public void client() {

        //1.通道
        SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 8585));
        FileChannel open = FileChannel.open(Paths.get("logs/log.log"), StandardOpenOption.READ);
        open.transferTo(0, open.size(), socketChannel);
        open.close();
        socketChannel.close();
    }


    /**
     * bio套接字
     */
    @SneakyThrows
    @Test
    public void server() {
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.bind(new InetSocketAddress(8585));

        while (serverSocketChannel.isOpen()) {
            SocketChannel accept = serverSocketChannel.accept();
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ByteBuffer allocate = ByteBuffer.allocate(1024);
            while (accept.read(allocate) != -1) {
                allocate.flip();
                baos.write(allocate.array());
                allocate.clear();
            }
            log.warn("{}", new String(baos.toByteArray()));
            baos.close();
            accept.close();
        }
    }


    /**
     * nio selector 套接字
     */
    @Test
    public void serverNio() throws IOException {
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.bind(new InetSocketAddress(8585));
        serverSocketChannel.configureBlocking(false);
        Selector selector = Selector.open();

        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        while (selector.select() > 0) {
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            selectionKeys.forEach(selectionKey -> {
                if (selectionKey.isAcceptable()) {
                    SocketChannel accept = null;
                    try {
                        accept = serverSocketChannel.accept();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    try {
                        accept.configureBlocking(false);
                        accept.register(selector, SelectionKey.OP_READ);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }

                } else if (selectionKey.isReadable()) {
                    SocketChannel channel = (SocketChannel) selectionKey.channel();
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    ByteBuffer allocate = ByteBuffer.allocate(1024);
                    try {
                        while (true) {
                            if (channel.read(allocate) == -1) break;
                            allocate.flip();
                            baos.write(allocate.array());
                            allocate.clear();
                        }
                        log.warn("{}", new String(baos.toByteArray()));
                        baos.close();
                        channel.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                selectionKeys.remove(selectionKey);
            });

        }
    }
}
